package com.lngsyz.ywtb.util.jwt;

import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lngsyz.ywtb.entity.LoginInfo;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import net.sf.json.JSONObject;

public class TokenUtil{
	
	private static final Logger LOGGER = LoggerFactory.getLogger(TokenUtil.class);
	
	private static final String CLAIM_KEY_INFO = "userinfo";
	private static final String CLAIM_KEY_CREATED = "created";
	/**
     * 生成token基本信息
     */
    public static final String JWT_SECRET = "iPanE1pA2sWo2dByZL";
    public static final Long JWT_EXPIRATION = 1800 * 60 * 1000L; // 30分钟
    
    /**
     * token position
     */
    public static final String AUTHORIZATION = "Authorization";
    /**
     * request中用户信息
     */
    public static final String LOGIN_USER = "login_user";

	
	/**
	 * 生成jwt token
	 * @param loginInfo 加密的内容
	 * @param secret 密钥
	 * @param expiration 过期时间
	 * @return String
	 */
	public static String generateToken(LoginInfo loginInfo){
		Map<String, Object> claims = new HashMap<>();
		claims.put(CLAIM_KEY_INFO, loginInfo);
		claims.put(CLAIM_KEY_CREATED, new Date());
		return Jwts.builder()
				.setClaims(claims)                                                                        // 自定义属性
				.setExpiration(new Date(Instant.now().toEpochMilli() + JWT_EXPIRATION))                // 过期时间 30分钟
				.signWith(SignatureAlgorithm.HS512, JWT_SECRET)                                           // 签名算法以及密匙
				.compact();
	}
	
	/**
	 * 从令牌中获取数据声明
	 *
	 * @param token
	 *            令牌
	 * @return 数据声明
	 */
	public static Claims getClaimsFromToken(String token) {
		Claims claims = null;
		if(StringUtils.isNotBlank(token)) {
			try {
				claims = Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJws(token).getBody();
			} catch (ExpiredJwtException e) {
				LOGGER.info("TOKEN 过期");
				claims = null;
				// TODO: handle exception
				// jwt 已经过期，在设置jwt的时候如果设置了过期时间，这里会自动判断jwt是否已经过期，如果过期则会抛出这个异常，我们可以抓住这个异常并作相关处理。
			} catch (Exception e) {
				LOGGER.error("业务异常信息：[{}]", e.getMessage(), e);
				claims = null;
			}
		}
		return claims;
	}
	
	/**
	 * 从令牌中获取用户名
	 *
	 * @param token
	 *            令牌
	 * @return 用户名
	 */
	public static LoginInfo getUserInfoFromToken(String token) {
		LoginInfo loginInfo = null;
		try {
			Claims claims = getClaimsFromToken(token);
			if(claims != null) {
				Object userInfo = claims.containsKey(CLAIM_KEY_INFO) ? claims.get(CLAIM_KEY_INFO) : null;
				if(userInfo != null) {
					loginInfo = (LoginInfo)JSONObject.toBean(JSONObject.fromObject(userInfo), LoginInfo.class);
				}
			}
		} catch (Exception e) {
			LOGGER.error("业务异常信息：[{}]", e.getMessage(), e);
			LOGGER.info("ERROR TOKEN:" + token);
			loginInfo = null;
		}
		return loginInfo;
	}

	/**
	 * 判断令牌是否过期
	 *
	 * @param token
	 *            令牌
	 * @return 是否过期
	 */
	public static Boolean isTokenExpired(String token) {
		try {
			Claims claims = getClaimsFromToken(token);
			if(claims != null) {
				Date expiration = claims.getExpiration();
				return expiration.before(new Date());
			} else {
				return false;
			}
		} catch (Exception e) {
			LOGGER.error("业务异常信息：[{}]", e.getMessage(), e);
			return false;
		}
	}
	
}
